package io.nanfeng.scope


interface TransactionalContext {
    fun begin()
    fun commit()
    fun rollback()
}

interface LockContext {
    fun lock(key: String)
    fun unlock(key: String)
}

data class Account(val id: Int, val name: String, var amount: Double)

class AccountService {


    context(LockContext,TransactionalContext)
    fun updateAccount(account: Account, amount: Double) {
//      1
        val lockContext: LockContext = this@LockContext
//      2
        val transactionalContext: TransactionalContext = this@TransactionalContext
        try {
            lockContext.lock(account.id.toString())
            try {
                transactionalContext.begin()
//                3
                updateAccountByRepository(account, amount)
            } catch (e: Throwable) {
                transactionalContext.rollback()
            } finally {
                transactionalContext.commit()
            }

        } finally {
            lockContext.unlock(account.id.toString())
        }
    }

    private fun updateAccountByRepository(account: Account, amount: Double) {
        account.amount += amount
    }
}

class LockContextImpl : LockContext {
    override fun lock(key: String) {
        println("lock $key")
    }

    override fun unlock(key: String) {
        println("unlock $key")
    }
}

class TransactionalContextImpl : TransactionalContext {
    override fun begin() {
        println("begin")
    }

    override fun commit() {
        println("commit")
    }

    override fun rollback() {
        println("rollback")
    }
}

fun main() {
    val account = Account(1, "nanfeng", 100.0)

    with(TransactionalContextImpl()){
        with(LockContextImpl()){
            AccountService().updateAccount(account, 100.0)
        }
    }
}